interface MessageTypeParamMap {
    'REGISTER': string
    'CLOSE_DIALOG': undefined
    'USERINFO': undefined
    'WINDOW': 'body' | 'frame'
    'DIALOG_STYLE': DialogStyle
    'RELOGIN': undefined
    'OPEN_MENU': OpenMenu | string
}

type OpenMenu = {
    name: string
    url: string
    icon: string
}

type DialogStyle = {
    width: string
    height: string
    top: string
}

interface MessageTypeResultMap {
    'REGISTER': MessageResult<string | undefined> | undefined
    'CLOSE_DIALOG': MessageResult<undefined> | undefined
    'USERINFO': MessageResult<UserInfo | undefined> | undefined
    'WINDOW': MessageResult<WindowInfo | undefined> | undefined
    'DIALOG_STYLE': MessageResult<undefined> | undefined
    'RELOGIN': MessageResult<undefined> | undefined
    'OPEN_MENU': MessageResult<undefined> | undefined
}

type UserInfo = {
    address: string
    avatar: string
    bbname: string | null
    email: string
    enterprisecode: string
    enterpriseid: number
    loginname: string
    moblephonenum: string
}

type MessageResult<T> = {
    code: string
    data: T
    msg: string
    success: boolean
}

type WindowInfo = {
    clientHeight: number,
    clientWidth: number,
    clientLeft: number,
    clientTop: number,
    offsetHeight: number,
    offsetLeft: number,
    offsetTop: number,
    offsetWidth: number,
    scrollWidth: number,
    scrollHeight: number,
    scrollLeft: number,
    scrollTop: number,
}


/**
 * frame bridge 客户端对象
 * 通过包装postMessage iframe 与宿主 之间的通信
 * prop clientId 客户端id 进行初始化后由宿主服务端返回
 * prop baseUrl 客户端url
 * prop timeout 调用超时时间设置
 * prop messageQueue 记录已发送消息, 超过超时时间 自动清理, 得到宿主响应 进行匹配 msgId 进行清理
 *  {   type:string //api type,
        msgId: string //消息唯一标识
        resolve?:(value:any)=>void //消息成功回调
        reject?:(value:any)=>void //消息失败回调
        timer: number // timeout 标识
    }
 *
 * method handleMessage(e:MessageEvent)=>void 接受宿主消息的处理
 * method init
 * method destroy
 * method sendAsync(type:string,data?:any)=>promise
 * method nativePostMessage
 *
 */
class Sdk {
    clientId: string | null = null
    url: string
    timeout: number
    sendList: {
        type: keyof MessageTypeParamMap,
        msgId: string,
        resolve?: (value: any) => void,
        reject?: (value: any) => void,
        timer?: number
    } [] = []
    messageHandle: (e: MessageEvent) => void

    constructor(timeout: number = 5) {
        this.url = `${window.location.origin}${window.location.pathname}`
        this.timeout = timeout
        this.messageHandle = (e) => {
            const {data} = e
            if (data && data.from === 'PORTAL') {
                const {type, data: payloadData, success, code, msg, msgId} = e.data
                let r = null
                while (true) {
                    if (type === 'REGISTER') {
                        if (success) {
                            this.clientId = payloadData
                        } else {
                            r = {data: payloadData, msg: `初始化失败！${msg}`, type}
                            break
                        }
                    }
                    r = {data: payloadData, success, code, msg}
                    break
                }
                const item = this.sendList.find(item => item.msgId === msgId)
                if (item) {
                    this.sendList.splice(this.sendList.indexOf(item), 1)
                    if (item.resolve && item.reject) {
                        clearTimeout(item.timer)
                        r.success ? item.resolve(r) : item.reject(r)
                    }
                } else {
                    console.warn(`{ type = ${type}, msgId = ${msgId} } 不存在`)
                }
            }
        }
    }

    init() {
        // if (this.clientId) return new Promise.reject("" )
        window.removeEventListener('message', this.messageHandle)
        window.addEventListener('message', this.messageHandle)
        window.addEventListener('unload', this.destroy)
        return this.send('REGISTER', this.url)
    }

    destroy() {
        window.removeEventListener('message', this.messageHandle)
        window.removeEventListener('unload', this.destroy)
        this.clientId = null
        this.sendList = []
    }

    send<T extends keyof MessageTypeParamMap, P extends MessageTypeParamMap[T], R extends MessageTypeResultMap[T]>(type: T, data?: P): Promise<R> {
        return new Promise<R | any>((resolve, reject) => {
            if (type !== 'REGISTER' && !this.clientId) {
                reject({data: null, msg: '初始化未完成！', type})
            }
            this.doPostMessage({type, data}, resolve, reject)
        })
    }

    doPostMessage<T extends keyof MessageTypeParamMap, P extends MessageTypeParamMap[T], R extends MessageTypeResultMap[T]>(msg: {
        type: T,
        data?: P
    }, resolve: (value: R) => void, reject: (value: any) => void) {
        const {data, type} = msg
        const message = {
            data,
            from: this.url,
            clientId: this.clientId,
            to: '*',
            type,
            msgId: `${new Date().getTime()}_${(Math.random() * 100) << 0}`,
            verifyCode: '',
        }
        const item = {type, msgId: message.msgId, resolve, reject, timer: undefined as any}
        if (resolve && reject) {
            item.timer = setTimeout(() => {
                reject({data: null, msg: '消息响应超时', type})
            }, this.timeout * 1000)
        }
        this.sendList.push(item)
        window.top.postMessage(message, message.to)
    }
}


export default Sdk
